package com.example.clw;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.background.SpriteBackground;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.ui.livewallpaper.BaseLiveWallpaperService;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;

import android.util.Log;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;

public class CLWService extends BaseLiveWallpaperService {
			
	//private static final String TAG = "TAG";
	static final int CAMERA_WIDTH = 318;
	private static final int CAMERA_HEIGHT = 480;
	private static float GRAVITY = 0.1f;
	private static final int SNOW_NUMBER = 30;
	static final int SNOW_SIZE = 16;
	
	static PhysicsWorld physicsWorld;
	
	private BitmapTextureAtlas bgBitmapTextureAtlas;
	private TextureRegion bgtTextureRegion;
	
	private BitmapTextureAtlas snowBitmapTextureAtlas;
	private TextureRegion  snowTextureRegion;
	
	private Scene scene;
	
	static Random generator;
	private List<Snow> snows;
	
	@Override
	public org.anddev.andengine.engine.Engine onLoadEngine() {
		Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions eo = new EngineOptions(true, ScreenOrientation.PORTRAIT, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
		eo.getTouchOptions().setRunOnUpdateThread(true);
		
		generator = new Random();
		snows = new ArrayList<Snow>();
		
		return new org.anddev.andengine.engine.Engine(eo);
	}
	@Override
	public void onLoadResources() {
		bgBitmapTextureAtlas = new BitmapTextureAtlas(512, 512, TextureOptions.DEFAULT);
		bgtTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bgBitmapTextureAtlas, this, "bg.jpg", 0, 0);
		
		snowBitmapTextureAtlas = new BitmapTextureAtlas(16, 16, TextureOptions.DEFAULT);
		snowTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(snowBitmapTextureAtlas, this, "snow.png", 0, 0);
		
		mEngine.getTextureManager().loadTexture(bgBitmapTextureAtlas);
		mEngine.getTextureManager().loadTexture(snowBitmapTextureAtlas);
	}
	@Override
	public Scene onLoadScene() {
		physicsWorld = new PhysicsWorld(new Vector2(0, GRAVITY), true);
		physicsWorld.setContactListener(createContactListener());
		
		scene = new Scene();
		
		Sprite bgSprite = new Sprite(0, 0, bgtTextureRegion);
		scene.setBackground(new SpriteBackground(bgSprite));
		
		
		Shape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2);
		final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);
		Shape left = new Rectangle(0, 0, 2, CAMERA_HEIGHT);
		Shape right = new Rectangle(CAMERA_WIDTH - 2, 0, 2, CAMERA_HEIGHT);
		
		// elasticity = dan hoi, friction = ma sat
		FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
		PhysicsFactory.createBoxBody(physicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
		PhysicsFactory.createBoxBody(physicsWorld, ground, BodyType.StaticBody, wallFixtureDef).setUserData("ground");
		PhysicsFactory.createBoxBody(physicsWorld, left, BodyType.StaticBody, wallFixtureDef);
		PhysicsFactory.createBoxBody(physicsWorld, right, BodyType.StaticBody, wallFixtureDef);
		
		scene.attachChild(roof);
		scene.attachChild(ground);
		scene.attachChild(left);
		scene.attachChild(right);
		
		for(int i = 0; i < SNOW_NUMBER; i++) {
			addSnow();
		}
		
		scene.registerUpdateHandler(physicsWorld);
		
		return scene;
	}
	@Override
	public void onLoadComplete() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onPauseGame() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onResumeGame() {
		// TODO Auto-generated method stub
		
	}
	
	private void addSnow() {
		int x = generator.nextInt(CAMERA_WIDTH - SNOW_SIZE);
		int y = generator.nextInt(2 * CAMERA_HEIGHT / 3);
		
		Snow snow = new Snow(x, y, SNOW_SIZE, SNOW_SIZE, snowTextureRegion);
		snow.mBody.setUserData(snow);
		snows.add(snow);
		scene.attachChild(snow);
	}
	
	private ContactListener createContactListener() {
		ContactListener contactListener = new ContactListener() {
			
			@Override
			public void preSolve(Contact contact, Manifold oldManifold) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void postSolve(Contact contact, ContactImpulse impulse) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void endContact(Contact contact) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void beginContact(Contact contact) {				
				Body bodyA = contact.getFixtureA().getBody();
				Body bodyB = contact.getFixtureB().getBody();
				Object dataA = bodyA.getUserData();
				Object dataB = bodyB.getUserData();								
				
				if(dataA == null || dataB == null)
					return;
				
				if(dataA instanceof Snow && dataB.equals("ground")) {					
					removeBodyAndShape(bodyA);
					snows.remove((Snow)dataA);					
					
					return;
				}
				
				if(bodyA.getUserData().equals("ground") && dataB instanceof Snow) {					
					removeBodyAndShape(bodyB);
					snows.remove((Snow)dataB);					
				}
			}
		};
		
		return contactListener;
	};
	
	
	private void removeBodyAndShape(final Body body) {
		final Snow snow = (Snow)body.getUserData();		
		final PhysicsConnector physicsConnector = physicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(snow);
		
		mEngine.runOnUpdateThread(new Runnable() {
			
			@Override
			public void run() {
				if(physicsConnector != null) {
					physicsWorld.unregisterPhysicsConnector(physicsConnector);
					body.setActive(false);
					physicsWorld.destroyBody(body);
					scene.detachChild(snow);
					
					addSnow();
				}
			}
		});
	}
}
